home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-03-06 | 6.2 KB | 182 lines | [TEXT/GEOL] |
- Item 3997645 1-Jan-91 13:53GMT
-
- From: UK0392 EHN & DIJ Oakley,BDV
-
- To: UK.DTS UK Developer Technical Support
-
- cc: MACAPP.TECH$ MacApp Technical
-
- ------------------------------------------------------------------------------
-
- Sub: A more elegant clipboard prob
-
- Friends,
-
- If you are looking for a little mental problem with which to see the New Year
- in, here is one which has been tickling me for a few hours, in getting the
- MacApp clipboard handling routines to cope with rather complex and different
- views:
-
- We are currently moving an application into V3.0, which allows a user to edit a
- 'panel' design for manufacture, using MacApp 2.0.1. Up to V2.0, we represented
- the panel as TDocument, to which there were two TWindows, one a simple text
- view, the other a graphical one. With V3.0, we have turned the text view into a
- complex spreadsheet-like view, with the following overall hierarchy:
-
- TPanlGWindow - graphics view
- /
- TPanlDocument
- \
- TPanlTWindow - spreadsheet view
- |
- TBaseView ( <-TView ) ------- simple view to make things easier
- |
- -----------------------------------------------------
- | |
- TPrimaryScroller (from USynchScroller) |
- | |
- TPanlTView ( <-TTextGridView ) - 2-col coordinate data |
- |
- --------------------------------------------------------
- | |
- TSecondaryScroller (2 others likewise)
- |
- TRowsView ( <-TTextGridView ) - 1-col row numbering
-
- - and TBaseView also has a few subsidiary TStaticText and TEditText views!
-
- By and large, this works very nicely (if a little finnicky in places), and
- USynchScroller does its job beautifully (thanks, Larry Tesler). The pain comes
- with Clipboard commands. We wanted to cut/copy the entire load to the
- clipboard, so that when the user opens the clipboard, he sees an identical set
- of linked scrolling views, as anything else would have been confusing and
- unmanageable for them.
-
- We implemented this by the following skeletal code:
-
- PROCEDURE TCutRCommand.ICutRCommand(...);
- BEGIN
- ICommand(...);
- {set up the various fields}
- {create the data structure containing the copied data}
- END;
-
- PROCEDURE TCutRCommand.DoIt; OVERRIDE;
- VARclipPanlView: TBaseView;
- clipDoc:TPanlDocument;
- aSize, aPos: VPoint;
- count: INTEGER;
- outline:Rect;
- fi: FailInfo;
-
- PROCEDURE CopyToClip;
- VAR aNewPanl: TPanl;
- BEGIN
- aNewPanl := TPanl(fThePanl.Clone);
- FailNil(aNewPanl);
- {and set up the handle fields too}
- clipDoc.fPanl := aNewPanl;
- END;
-
- PROCEDURE HdlFailure(error: OSErr; message: LONGINT);
- BEGIN
- clipDoc.Free;
- END;
-
- BEGIN
- {cut the data out of the original panel}
- {now, initialise our Clipboard version of TPanlDocument}
- New(clipDoc);
- FailNIL(clipDoc);
- clipDoc.IPanlDocument(TRUE);
- fClipDocument := clipDoc;
-
- CatchFailures(fi, HdlFailure);
-
- {DoClipViews actually uses the resource view to construct those views
- needed for the clipDoc - it is v similar to DoMakeViews, but a bit more
- spartan. The problem arises here because we cannot set up the clipPanlView
- using more conventional procedural techniques, as in the many examples ?}
- clipDoc.DoClipViews;
- clipPanlView := clipDoc.fBaseView;
-
- IF fView.Focus THEN ;
-
- CopyToClip;
-
- {Make sure the Cut left us with enough memory to continue.}
- FailSpaceIsLow;
- Success(fi);
-
- gApplication.ClaimClipboard(clipPanlView);
-
- {this final method call makes sure that all the altered views are
- correctly filled, sized, topped & tailed}
- UpdateViews;
- END;
-
- The problem is that, on the third (and subsequent) clipboard command, when
- Application.AbandonUndoClipboard is called to dispose of gClipUndoView, there
- is confusion as to the existence of gClipUndoView - it is given as already
- being freed, but patently has not been freed!
-
- Our kludge to work around this (far from elegant, but it works without any
- memory or handle leakage) is:
-
- PROCEDURE TPanellistApplication.AbandonUndoClipboard; OVERRIDE;
- VAR aDoc: TDocument;
- BEGIN
- IF gClipUndoView <> NIL THEN
- BEGIN
- {$IFC qDebug}
- IF gClipUndoView = gClipView THEN
- ProgramBreak('About to Free view both in clip and undo Clip!');
- {$ENDC}
- aDoc := gClipUndoView.fDocument;
- IF (aDoc <> NIL) THEN TPanlDocument(aDoc).FreeForClip;
- {note that if we do *not* call this, we just accumulate orphaned views and
- windows}
- gClipUndoView := NIL;
- END;
- END;
-
- PROCEDURE TPanlDocument.FreeForClip;
- VAR wmgrWindow: WindowPtr;
- BEGIN
- {this is a paraphrased & reordered version of TDocument.Free which is the only
- one which actually works!}
- fPanl.Free; {our local data object}
- gApplication.DeleteDocument(SELF);
- FreeIfObject(fBaseView); {*must* be here before freeing views etc., or it is
- given as being freed already}
- wmgrWindow := fPanlTWindow.fWMgrWindow;
- wmgrWindow := FreeIfWMgrWindow(wmgrWindow, TRUE); {dispose of WMgr window}
- fPanlTWindow.fSubViews.ShallowFree; {just get rid of the list - its contents
- have already been freed!}
- fPanlTWindow.ShallowFree; {just get rid of the window itself}
- fWindowList.ShallowFree; {just get rid of the window list itself, as its
- contents have already been disposed of}
- fViewList.ShallowFree; {ditto for the view list}
-
- {and the rest is much the same as for TDocument.Free}
- IF fSharePrintInfo THEN
- fPrintInfo := DisposeIfHandle(fPrintInfo);
- fPrintInfo := NIL; { Always drop my reference }
-
- Handle(fTitle) := DisposeIfHandle(fTitle);
- IF gTarget = SELF THEN
- IF fNextHandler = NIL THEN
- gApplication.SetTarget(gApplication)
- ELSE
- gApplication.SetTarget(fNextHandler);
-
- fNextHandler := NIL;
- ShallowFree;
- END;
-
- There must be a more elegant solution - any ideas?
-
- Regards & a very successful New Year,
- Howard Oakley.
-
-